{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import itk\n",
    "\n",
    "from itkwidgets import view"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "PixelType = itk.F\n",
    "Dimension = 3\n",
    "    \n",
    "# Read tre file\n",
    "tubesReader = itk.SpatialObjectReader[Dimension].New()\n",
    "tubesReader.SetFileName(\"Data/MRI-Normals/Normal071-VascularNetwork.tre\")\n",
    "tubesReader.Update()\n",
    "tubes = tubesReader.GetGroup()\n",
    "\n",
    "# Read mra image\n",
    "mraReader = itk.ImageFileReader[itk.Image[PixelType, Dimension]].New()\n",
    "mraReader.SetFileName(\"Data/MRI-Normals/Normal071-MRA.mha\")\n",
    "mraReader.Update()\n",
    "mra = mraReader.GetOutput()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4bbce8b806fe46bfa9d33ab61ae64724",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Viewer(geometries=[], gradient_opacity=0.22, point_set_colors=array([[0.8392157, 0.       , 0.       ]], dtype…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "view(image=mra, point_sets=tubes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of objects =  265\n",
      "Children are all maintained as base spatial object types - not as tubes, groups, landmarks, etc.\n",
      "  You can print info about the object:\n",
      "TubeSpatialObject (0000027255258D50)\n",
      "  TubeSpatialObject(0000027255258D50)\n",
      "  End Type : 1\n",
      "  Parent Point : -1\n",
      "  Root : 1\n",
      "  PointBasedSpatialObject(0000027255258D50)\n",
      "  Number of points: 4330\n",
      "  RTTI typeinfo:   class itk::TubeSpatialObject<3,class itk::TubeSpatialObjectPoint<3> >\n",
      "  Reference Count: 4\n",
      "  Modified Time: 4477\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Source: (none)\n",
      "  Source output name: (none)\n",
      "  Release Data: Off\n",
      "  Data Released: False\n",
      "  Global Release Data: Off\n",
      "  PipelineMTime: 0\n",
      "  UpdateMTime: 0\n",
      "  RealTimeStamp: 0 seconds \n",
      "  Id:0\n",
      "  TypeName:VesselTubeSpatialObject\n",
      "  ParentId:265\n",
      "  Parent:000002725D1E1920\n",
      "  LargestPossibleRegion:ImageRegion (0000027255258E90)\n",
      "  Dimension: 3\n",
      "  Index: [0, 0, 0]\n",
      "  Size: [0, 0, 0]\n",
      "\n",
      "  RequestedRegion:ImageRegion (0000027255258EC8)\n",
      "  Dimension: 3\n",
      "  Index: [0, 0, 0]\n",
      "  Size: [0, 0, 0]\n",
      "\n",
      "  BufferedRegion:ImageRegion (0000027255258F00)\n",
      "  Dimension: 3\n",
      "  Index: [0, 0, 0]\n",
      "  Size: [0, 0, 0]\n",
      "\n",
      "  My Bounding Box In Object Space:\n",
      "  BoundingBox (000002727115CD90)\n",
      "  RTTI typeinfo:   class itk::BoundingBox<unsigned __int64,3,double,class itk::VectorContainer<unsigned __int64,class itk::Point<double,3> > >\n",
      "  Reference Count: 2\n",
      "  Modified Time: 26\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Bounding Box: ( 0,0 0,0 0,0  )\n",
      "\n",
      "  My Bounding Box In World Space:\n",
      "  BoundingBox (000002727115D510)\n",
      "  RTTI typeinfo:   class itk::BoundingBox<unsigned __int64,3,double,class itk::VectorContainer<unsigned __int64,class itk::Point<double,3> > >\n",
      "  Reference Count: 2\n",
      "  Modified Time: 27\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Bounding Box: ( 0,0 0,0 0,0  )\n",
      "\n",
      "  Family Bounding Box In Object Space:\n",
      "  BoundingBox (000002727115E690)\n",
      "  RTTI typeinfo:   class itk::BoundingBox<unsigned __int64,3,double,class itk::VectorContainer<unsigned __int64,class itk::Point<double,3> > >\n",
      "  Reference Count: 2\n",
      "  Modified Time: 28\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Bounding Box: ( 0,0 0,0 0,0  )\n",
      "\n",
      "  Family Bounding Box In World Space:\n",
      "  BoundingBox (000002727115C430)\n",
      "  RTTI typeinfo:   class itk::BoundingBox<unsigned __int64,3,double,class itk::VectorContainer<unsigned __int64,class itk::Point<double,3> > >\n",
      "  Reference Count: 2\n",
      "  Modified Time: 29\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Bounding Box: ( 0,0 0,0 0,0  )\n",
      "\n",
      "  Object to World Transform: AffineTransform (000002726F767FE0)\n",
      "  RTTI typeinfo:   class itk::AffineTransform<double,3>\n",
      "  Reference Count: 2\n",
      "  Modified Time: 4475\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Matrix: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Offset: [0, 0, 0]\n",
      "  Center: [0, 0, 0]\n",
      "  Translation: [0, 0, 0]\n",
      "  Inverse: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Singular: 0\n",
      "\n",
      "  Object to World Transform Inverse: AffineTransform (000002726F7681D0)\n",
      "  RTTI typeinfo:   class itk::AffineTransform<double,3>\n",
      "  Reference Count: 2\n",
      "  Modified Time: 4476\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Matrix: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Offset: [-0, -0, -0]\n",
      "  Center: [0, 0, 0]\n",
      "  Translation: [0, 0, 0]\n",
      "  Inverse: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Singular: 0\n",
      "\n",
      "  Object to Parent Transform: AffineTransform (000002726F768990)\n",
      "  RTTI typeinfo:   class itk::AffineTransform<double,3>\n",
      "  Reference Count: 2\n",
      "  Modified Time: 4469\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Matrix: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Offset: [0, 0, 0]\n",
      "  Center: [0, 0, 0]\n",
      "  Translation: [0, 0, 0]\n",
      "  Inverse: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Singular: 0\n",
      "\n",
      "  Object to Parent Transform Inverse: AffineTransform (000002726F767DF0)\n",
      "  RTTI typeinfo:   class itk::AffineTransform<double,3>\n",
      "  Reference Count: 2\n",
      "  Modified Time: 4470\n",
      "  Debug: Off\n",
      "  Object Name: \n",
      "  Observers: \n",
      "    none\n",
      "  Matrix: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Offset: [-0, -0, -0]\n",
      "  Center: [0, 0, 0]\n",
      "  Translation: [0, 0, 0]\n",
      "  Inverse: \n",
      "    1 0 0 \n",
      "    0 1 0 \n",
      "    0 0 1 \n",
      "  Singular: 0\n",
      "\n",
      "\n",
      "\n",
      "  Object properties: \n",
      "  ChildrenList:0\n",
      "  DefaultInsideValue:1\n",
      "  DefaultOutsideValue:0\n",
      "\n",
      "  But you cannot call member functions in derived classes (e.g., TubeSO member functions):\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'itkSpatialObject3' object has no attribute 'GetNumberOfPoints'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-4-49cb51651c9d>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbaseSO\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"  But you cannot call member functions in derived classes (e.g., TubeSO member functions):\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbaseSO\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mGetNumberOfPoints\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m   \u001b[1;31m# This command fails - it should fail...and the next cell shows the fix...\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'itkSpatialObject3' object has no attribute 'GetNumberOfPoints'"
     ]
    }
   ],
   "source": [
    "print(\"Number of objects = \", tubes.GetNumberOfChildren())\n",
    "\n",
    "sobj = tubes.GetChildren(0, \"VesselTube\")\n",
    "baseSO = sobj[0]\n",
    "\n",
    "print(\"Children are all maintained as base spatial object types - not as tubes, groups, landmarks, etc.\")\n",
    "print(\"  You can print info about the object:\")\n",
    "print(baseSO)\n",
    "print(\"  But you cannot call member functions in derived classes (e.g., TubeSO member functions):\")\n",
    "print(baseSO.GetNumberOfPoints())   # This command fails - it should fail...and the next cell shows the fix..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "One option is to downcast each object in the children list, as needed\n",
      "  Now we can call member functions of the derived class\n",
      "4330\n"
     ]
    }
   ],
   "source": [
    "print(\"One option is to downcast each object in the children list, as needed\")\n",
    "\n",
    "baseSOTyped = itk.down_cast(baseSO)\n",
    "\n",
    "print(\"  Now we can call member functions of the derived class\")\n",
    "print(baseSOTyped.GetNumberOfPoints())   # This command succeeds on the down-casted variable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Another option is to use CastSpatialObject class to convert base spatial objects of a particular type...\n"
     ]
    }
   ],
   "source": [
    "print(\"Another option is to use CastSpatialObject class to convert base spatial objects of a particular type...\")\n",
    "castSO = itk.CastSpatialObjectFilter[3].New()\n",
    "castSO.SetInput(tubes)\n",
    "tubesSO = castSO.GetTubes()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Then you can access its member functions...\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "itkPointD3 ([121.292, 94.4135, 0.313261])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(\"Then you can access its member functions...\")\n",
    "tube = tubesSO[0]\n",
    "tube.GetPoints()[1].GetPositionInObjectSpace()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "307571806b704f9db5c30e54bb4f7d2d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Viewer(geometries=[], gradient_opacity=0.22, point_sets=[], rendered_image=<itk.itkImagePython.itkImageF3; pro…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "p = list(map(lambda x: tube.GetPoint(x).GetPositionInObjectSpace(), range(tube.GetNumberOfPoints())))\n",
    "i = list(map(lambda x: mra.TransformPhysicalPointToIndex( x ), p ))\n",
    "for x in i:\n",
    "    mra.SetPixel(x, 10000)\n",
    "    \n",
    "view(mra)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
